﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Gert3D
{
  public class Camera
  {
    private Matrix _transform = Matrix.Identity;
    private double _fieldOfView = 45.0f;
    private int _width = 640;
    private int _height = 480;

    public Camera()
    {
    }

    public Matrix Transform
    {
      get { return _transform; }
      set { _transform = value; }
    }

    public double FieldOfView
    {
      get { return _fieldOfView; }
      set { _fieldOfView = value; }
    }

    public int Width
    {
      get { return _width; }
      set { _width = value; }
    }

    public int Height
    {
      get { return _height; }
      set { _height = value; }
    }

    /// <summary>
    /// Calculates a ray for each pixel of the image in world space.
    /// </summary>
    /// <returns>A list of all calculated rays.</returns>
    public Ray[,] CalculateRays()
    {
      double radAngle = (Math.PI / 180.0) * (_fieldOfView / 2f);
      double halfWidth = Math.Tan(radAngle);
      double planeWidth = halfWidth * 2f;

      double aspect = (double)_width / _height;
      double planeHeight = planeWidth / aspect;

      double stepX = planeWidth / _width;
      double stepY = planeHeight / _height;

      double startX = -halfWidth;
      double startY = planeHeight / 2f;

      Ray[,] result = new Ray[_width, _height];

      Vector3 origin = _transform.Multiply(new Vector3());

      for (int y = 0; y < _height; y++)
      {
        double v = startY - y * stepY;
        for (int x = 0; x < _width; x++)
        {
          double u = startX + x * stepX;
          Ray r = new Ray();
          r.Length = 1000f;
          r.Direction._x = u;
          r.Direction._y = v;
          r.Direction._z = 1.0;
          r.Direction = _transform.Multiply(r.Direction);
          r.Origin = origin;
          r.Direction.Normalize();
          result[x, y] = r;
        }

      }

      return result;
    }

  }
}
